package DARP;
/**
 * Classe responsável por ler e carregar os dados para a execução do DARP
 */


import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Scanner;



public class Data {


	private static int[] garagensIniciais = null;
	private static int[] garagensFinais = null;
	private float matriz[][], t[][];
	private int demanda[];
	private boolean cidStatus[];
	private int nCidades;
	private int nVeiculos;
	private int[] veiculos;
	private int[] custos;
	private static Data instance = null;

	public static String instancias = "Instancias/instanciaFormatada.txt";//"Instancias/instanciaReduzida";//  

	private int quantidadeDeVeiculos;
	private int quantidadeDePontosDeColetas;
	private int tempoMaxDeDuracaoDaRota;
	private int capacidadeDoVeiculo;
	private int tempoMaxDeViagemCliente;

	private int[] id;
	private float[] coordX;
	private float[] coordY;
	private float[] tempoServico;
	private int[] acao;
	private float[] inicioJanela;
	private float[] fimJanela;


	//	private static int peso = 10000;
	//	private static int vizinhos = 15;
	//	private static int btMax = 150;
	//	private static double alfa = 0.7;
	//	private static int lBtSize = 10;
	//	private static int graspMax = 100;

	public Data(BufferedReader bufferedReader) {
		readCitiesData(bufferedReader);
		//		readTrucksData(trucks);
		cidStatus = new boolean[quantidadeDePontosDeColetas+2];
		clearStatus();
	}

	public void readCitiesData(BufferedReader buff) {
		try {

			String linhaDeEntrada;
			Integer countLinha = 0;

			buff.ready();
			linhaDeEntrada = buff.readLine();

			Scanner stoken = new Scanner(linhaDeEntrada); 
			quantidadeDeVeiculos = Integer.parseInt(stoken.next().trim());
			//System.out.println("Lendo : "+quantidadeDeVeiculos);
			quantidadeDePontosDeColetas = Integer.parseInt(stoken.next().trim());
			tempoMaxDeDuracaoDaRota = Integer.parseInt(stoken.next().trim());
			capacidadeDoVeiculo = Integer.parseInt(stoken.next().trim());
			tempoMaxDeViagemCliente = Integer.parseInt(stoken.next().trim());

			System.out.println(quantidadeDeVeiculos);
			System.out.println(quantidadeDePontosDeColetas);
			System.out.println(tempoMaxDeDuracaoDaRota);
			System.out.println(capacidadeDoVeiculo);
			System.out.println(tempoMaxDeViagemCliente);

			//			float cidades[] = new float[quantidadeDePontosDeColetas];
			//			float vVeiculos[] = new float[quantidadeDeVeiculos];
			id = new int[quantidadeDePontosDeColetas + quantidadeDeVeiculos];
			coordX = new float[quantidadeDePontosDeColetas+quantidadeDeVeiculos];
			coordY = new float[quantidadeDePontosDeColetas + quantidadeDeVeiculos];
			tempoServico = new float[quantidadeDePontosDeColetas + quantidadeDeVeiculos];
			acao = new int[quantidadeDePontosDeColetas+quantidadeDeVeiculos];
			inicioJanela = new float[quantidadeDePontosDeColetas+quantidadeDeVeiculos];
			fimJanela = new float[quantidadeDePontosDeColetas+quantidadeDeVeiculos];
			//this.cidStatus = new boolean[quantidadeDePontosDeColetas +1];

			int i = 0;

			while (buff.ready()) {
				linhaDeEntrada = buff.readLine();


				stoken = new Scanner(linhaDeEntrada); 

				countLinha++;
				while (stoken.hasNext() ){
					/*
					Justificando o porque de termos [7]
					1 - identificador do ponto
					2 - coordenada x
					3 - coordenada y 
					4 - tempo de servico no ponto
					5 - 0=garagem, 1=coleta, -1=entrega
					6 - horario de inicio da janela de tempo
					7 - horario de termino da janela de tempo 
					 */
					id[i] = Integer.parseInt(stoken.next().trim());
					System.out.println(id[i]);
					coordX[i] = Float.parseFloat(stoken.next().trim());
					//System.out.println(coordX[i]);
					coordY[i] = Float.parseFloat(stoken.next().trim()); 
					//System.out.println(coordY[i]);
					tempoServico[i] = Float.parseFloat(stoken.next().trim());
					//System.out.println(tempoServico[i]);
					acao[i] = Integer.parseInt(stoken.next().trim());
					//	System.out.println(acao[i]);
					inicioJanela[i] = Float.parseFloat(stoken.next().trim());
					fimJanela[i] = Float.parseFloat(stoken.next().trim());

					i++;
				}
			}	
			buff.close();
			//setVetores(id, coordX, coordY,tempoServico,acao,inicioJanela,fimJanela);
			//setVeiculos();
			clearStatus();
			setGaragens();
			calcula_distancias();
		}catch (FileNotFoundException ex) {
			ex.printStackTrace();
		} catch (IOException ex) {
			ex.printStackTrace();
		}

	}

	public int getTempoMaxDeDuracaoDaRota() {
		return tempoMaxDeDuracaoDaRota;
	}

	public int getTempoMaxDeViagemCliente() {
		return tempoMaxDeViagemCliente;
	}

	private void setVetores(int[] id, float[] coordX, float[] coordY,
			float[] tempoServico, int[] acao, float[] inicioJanela,
			float[] fimJanela) {
		this.id = id;
		this.coordX = coordX;
		this.coordY = coordY;
		this.tempoServico = tempoServico;
		this.acao = acao;
		this.inicioJanela = inicioJanela;
		this.fimJanela = fimJanela;
	}

	public int[] getId(){
		return this.id;
	}
	public float[] getCoordX(){
		return this.coordX;
	}

	public float[] getCoordY(){
		return this.coordY;
	}
	public float[] getTempoServico(){
		return this.tempoServico;
	}
	public int[] getAcao(){
		return this.acao;
	}
	public float[] getInicioJanela(){
		return this.inicioJanela;
	}
	public float[] getFimJanela(){
		return this.fimJanela;
	}


	public int[] getVeiculos(){
		//System.out.println("Quantidade de Veiculos" + quantidadeDeVeiculos);
		veiculos = new int[quantidadeDeVeiculos];
		for (int i = 0; i < quantidadeDeVeiculos; i++) {
			veiculos[i] = i;
		}
		return veiculos;
	}

	private void calcula_distancias() {
		matriz = new float[coordX.length][coordY.length];
		t = new float[coordX.length][coordY.length];
		System.out.println("Matriz de Distancia");
		for (int i = 0; i < coordX.length; i++) {
			//				System.out.println("==================");
			//				System.out.println("I"+ i);
			//				System.out.println("==================");

			for (int j = 0; j < coordY.length; j++) {
				matriz[i][j] = 0;
				t[i][j] = 0;
				if (i == j) {
					matriz[i][j] = Integer.MAX_VALUE;
					t[i][j] = Integer.MAX_VALUE;
				}else{
					double dx = Math.pow((coordX[j] - coordX[i]), 2);
					double dy = Math.pow((coordY[j] - coordY[i]), 2);
					matriz[i][j] = (int) Math.sqrt(dx + dy);
					t[i][j] = matriz[i][j]/20 ; 
					//System.out.println("I"+i+"J"+j+" Valor: "+ matriz[i][j]);
				}
			}
			//System.out.println("==================");
		}
	}


	public float[][] getT() {
		return t;
	}

	public int retornaMenorDistacia(int elementoComparado, float[][] matrizDistancia) {
		// TODO VERIFICAR OS 2 ENTRADA E SAIDA (METADE DO N)
		float min = Integer.MAX_VALUE;
		int  elementoRetornado = 0;
		//System.out.println("Elemento comparado no retornaMenorDist"+ elementoComparado);
		if(elementoComparado < (quantidadeDePontosDeColetas/2)){
			//while(cont < (quantidadeDePontosDeColetas/2)){
			
		//	System.out.println("Elemento ("+elementoComparado+"->"+elementoRetornado+")");
			
			for (int i = 0; i <= (quantidadeDePontosDeColetas/2); i++) {		
//				System.out.println("Elemento ("+elementoComparado+"->"+elementoRetornado+")");
				if (i!=elementoComparado)
					if( min > matrizDistancia[elementoComparado][i] 
					  && !isVisited(i)){
						elementoRetornado = i;
					min =  matrizDistancia[elementoComparado][i];
			//		System.out.println("Elemento ("+elementoComparado+"->"+elementoRetornado+") = "+min);
				}
			}
		}
//		else
//			for (int i = 0; i < (quantidadeDePontosDeColetas); i++) {		
//
//				if (i!=elementoComparado)
//					if( min > matrizDistancia[elementoComparado][i] && !isVisited(i)){
//				
//					min =  matrizDistancia[elementoComparado][i];
//					elementoRetornado = i;
//				}
//			}
		//			while(cont < matrizDistancia.length){
		//				if (min < matrizDistancia[elementoComparado][i]){
		//					min =  matrizDistancia[elementoComparado][i];
		//					elementoRetornado = j;
		//				}
		//				cont++;
		//			}
		
		if (elementoRetornado != 0 ){
		//	System.out.println("Elemento ("+elementoComparado+"->"+elementoRetornado+") distancia é "+min);
			if (elementoRetornado == Integer.MAX_VALUE) {
				return 0;
			}
			return elementoRetornado;
			
		}
		return 999;
	}
	
	public int getCapacidadeDoVeiculo() {
		return capacidadeDoVeiculo;
	}

	public int[] getCapacidadeDosVeiculos() {
		int[] capacidadeDosVeiculo = new int[quantidadeDeVeiculos];
		for (int i = 0; i < capacidadeDosVeiculo.length; i++) {
			capacidadeDosVeiculo[i] = capacidadeDoVeiculo;
		}
		return capacidadeDosVeiculo;
	}
	
	private void setGaragens(){
		garagensIniciais = new int [quantidadeDeVeiculos];
		garagensFinais = new int [quantidadeDeVeiculos];
		System.out.println(quantidadeDeVeiculos);
		int cont = 0;
		while (cont < quantidadeDeVeiculos){
			garagensIniciais[cont] = id[0];
			garagensFinais[cont] = id[0];
			cont++;
		}

	}

	public int[] getGaragensIniciais(){
		return garagensIniciais;
	}

	private void setGaragensFinais(){
		garagensIniciais = new int [quantidadeDeVeiculos];
		int cont = 0;
		while (cont <quantidadeDeVeiculos){
			garagensIniciais[cont] = id[quantidadeDeVeiculos];
		}

	}

	public int[] getGaragensFinais(){

		return (int[]) garagensIniciais;
	}

	

	public int getQuantidadeDePontosDeColetas() {
		return quantidadeDePontosDeColetas;
	}

	public int getQuantidadeDeVeiculos() {
		return quantidadeDeVeiculos;
	}

	public void setQuantidadeDeVeiculos(int quantidadeDeVeiculos) {
		this.quantidadeDeVeiculos = quantidadeDeVeiculos;
	}

	public float[][] getMatriz() {
		return matriz;
	}

	public int getCapacityOfTruck(int t) {
		return veiculos[t];
	}

	public int getCostOfTruck(int t) {
		return custos[t];
	}

	public int getDemanda(int c) {
		return demanda[c-1];
	}

	public float getDistancia(int origem, int fim) {
		return matriz[origem][fim];
	}

	public static Data getPRVData() {


		if (instance == null)
			try {
				instance = new Data(
						new BufferedReader(new FileReader(new File(instancias))));
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			return instance;

	}

	public void clearStatus() {
		for (int i = 0; i < nCidades; i++) {
			cidStatus[i] = false;
		}
	}

	public boolean isVisited(int cid) {
		if(cid<=0 || cid >=quantidadeDePontosDeColetas+1) return true;
		return cidStatus[cid];
	}

	public void setRequisicoesVisitadas(int id1, int id2) {
		cidStatus[id1] = true; 
		cidStatus[id2] = true;
		System.out.println("Elemento "+ id1+ " Marcado como: "+cidStatus[id1]);
		System.out.println("Elemento "+ id2+ " Marcado como: "+cidStatus[id2]);

	}

	public LinkedList<Integer> getNotVisited() {
		LinkedList<Integer> l = new LinkedList<Integer>();//int[quantidadeDePontosDeColetas - getNumOfVisited()];
		
		for (int i = 0; i < quantidadeDePontosDeColetas; i++) {
			if (!cidStatus[i]) {
				l.add(id[i]);
			}
		}
		return l;
	}

	public int getNumOfVisited() {
		int n = 0;
		for (int i = 0; i < quantidadeDePontosDeColetas; i++) {
			if (cidStatus[i])
				n++;
		}
		return n;
	}

	public int getNCaminhoes() {
		return nVeiculos;
	}

	public int getNCidades() {
		return nCidades;
	}

	//	public static void setPeso(int p) {
	//		peso = p;
	//	}
	//
	//	public int getPeso() {
	//		return peso;
	//	}

	public static int random(int n) {
		return (int) (Math.random() * n);
	}

	public static int random(int n1, int n2) {
		return (int) (Math.random() * (n2 - n1)) + n1;
	}

	public void printData() {
		for(int i = 0; i < matriz.length;i++){
			for(int j = 0; j < matriz[i].length;j++)
				System.out.println((i) + " - > " + (j)+ " " + matriz[i][j] + " ");
		}     
	}


	
	//	/**
	//	 * @return
	//	 */
	//	public static int getVizinhos() {
	//		return vizinhos;
	//	}
	//
	//	/**
	//	 * @param i
	//	 */
	//	public static void setVizinhos(int i) {
	//		vizinhos = i;
	//	}
	//
	//	/**
	//	 * @return
	//	 */
	//	public static double getAlfa() {
	//		return alfa;
	//	}
	//
	//	/**
	//	 * @return
	//	 */
	//	public static int getBtMax() {
	//		return btMax;
	//	}
	//
	//	/**
	//	 * @return
	//	 */
	//	public static int getLBtSize() {
	//		return lBtSize;
	//	}
	//
	//	/**
	//	 * @return
	//	 */
	//	public static int getGraspMax() {
	//		return graspMax;
	//	}
	//
	//	/**
	//	 * @param i
	//	 */
	//	public static void setGraspMax(int i) {
	//		graspMax = i;
	//	}
	//
	//	/**
	//	 * @param i
	//	 */
	//	public static void setLBtSize(int i) {
	//		lBtSize = i;
	//	}
	//
	//	/**
	//	 * @param i
	//	 */
	//	public static void setBtMax(int i) {
	//		btMax = i;
	//	}


}